#include "SizedMessageQueue.h"
#include "../common/StringUtils.h"

namespace ipc
{

SizedMessageQueue::SizedMessageQueue( int id , std::string filename,char key) :
        m_id( id ),m_fileName(filename),m_key(key)
{
}

SizedMessageQueue::~SizedMessageQueue()
{
}

void SizedMessageQueue::put( MessageId_t mtype, void* data, int size)
{
    std::string error;
    MQAMessage message;
    message.mtype = mtype;
    memcpy(message.data, data, size);
    if ( msgsnd( this->m_id, ( const void * ) &message, size, 0 ) < 0 )
    {
        error = strerror( errno );
        throw Exception( "Error writing the message queue: "+m_fileName+"key:"+m_key+ ": " + error );
    }
}

int SizedMessageQueue::get( MessageId_t tipo,  void* data, int size)
{
    std::string error;
    MQAMessage message;

    if ( msgrcv( this->m_id, ( void * ) &message, size, tipo, 0 ) < 0 )
    {
        error = strerror( errno );
        throw Exception( "Error reading the message queue "+m_fileName+" size "+StringUtils::NumberToString(size)+" : " + error );
    }
    memcpy(data, message.data, size);

    return message.mtype;
}

SizedMessageQueue SizedMessageQueue::create( std::string file, int charKey,
        int flags )
{
    std::string error;
    std::string touchCmd;
    int key;
    int id;
    touchCmd = "touch " + file;
    system( touchCmd.c_str() );
    key = ftok( file.c_str(), charKey );
    if ( key < 0 )
    {
        error = strerror( errno );
        throw Exception(
                "Error in the message queue key on file: " + file + ". Error: "
                        + error );
    }
    flags |= MQ_PERMS;
    id = msgget( key, flags );
    if ( id < 0 )
    {
        error = strerror( errno );
        throw Exception( "Error creating the message queue "+file +": " + error );
    }
    return SizedMessageQueue( id ,file,key);
}


SizedMessageQueue SizedMessageQueue::get( std::string file, int charKey )
{
    return SizedMessageQueue::create( file, charKey, IPC_EXCL );
}

void SizedMessageQueue::destroy( std::string file, int charKey )
{
    std::string error;
    SizedMessageQueue mq = SizedMessageQueue::get( file, charKey );
    if ( msgctl( mq.m_id, IPC_RMID, NULL ) )
    {
        error = strerror( errno );
        throw Exception(
                "Error while destroying the message queue. Error: " + error );
    }
}


} /* namespace ipc */
